package vn.raz.brainnydefense;

import java.util.Random;

import vn.raz.bmspriter.libgdxrenderer.BMSLibgdxRenderer;
import vn.raz.brainnydefense.object.BulletObject;
import vn.raz.brainnydefense.object.DamageStage;
import vn.raz.brainnydefense.object.GameObject;
import vn.raz.brainnydefense.object.PlantStage;
import vn.raz.brainnydefense.object.Zombie;
import vn.raz.brainnydefense.ultility.Assets;
import vn.raz.brainnydefense.ultility.OverlapTester;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.GLCommon;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.Array;

public class GameScreen implements Screen, InputProcessor{
	
	MainGame game;
	OrthographicCamera guiCam;
	SpriteBatch batcher;
	BMSLibgdxRenderer   bmsRenderer;
	Vector3 touchpos;
	Vector2 gravity;
	Random rand;
	
	Rectangle playBounds;
	GameObject[][] listBox;
	Array<Zombie> zombies;
	Array<GameObject> chosedBox;
	Array<GameObject> newBox;
	Array<GameObject> checkbox;
	Array<PlantStage> plantStages;
	Array<BulletObject> bullets;
	Array<DamageStage> dameStages;
	
	int[] addbox;
	int boxBound;
	
	float time;
	float nexttime;
	
	public boolean[][] isChecked;
	public boolean ischeckok;
	
	public GameScreen(MainGame game){
		this.game = game;
		guiCam = new OrthographicCamera(480, 800);
		guiCam.position.set(480 / 2, 800 / 2, 0);
		batcher = new SpriteBatch();
		bmsRenderer = new BMSLibgdxRenderer(batcher);
		touchpos = new Vector3();
		rand = new Random();
		gravity = new Vector2(0, -500);

		boxBound = 70;
		addbox = new int[6];
		playBounds = new Rectangle(20, 40, 440, 440);
		listBox = new GameObject[6][6];
		zombies = new Array<Zombie>();
		chosedBox = new Array<GameObject>();
		newBox = new Array<GameObject>();
		checkbox = new Array<GameObject>();
		plantStages = new Array<PlantStage>();
		bullets = new Array<BulletObject>();
		dameStages = new Array<DamageStage>();
	}
	
	public void setNewGame(){
		time = 0;
		nexttime = 0;
		for(int i=0;i<6;i++)	addbox[i] = 6;
		addBox();
	}
	
	public void checkMatrix(){
		while(!ischeckok){
			checkForFirst(6, 6);
			if(!ischeckok){
				for(int i=0;i<6;i++)
					for(int j=0;j<6;j++)
						listBox[i][j] = null;
				for(int i=0;i<6;i++)	addbox[i] = 6;
				addBox();
			}
		}
	}
	
	public void addBox(){
		int t;
		for(int i=0;i<6;i++)
			for(int j=0;j<addbox[i];j++){
				t = rand.nextInt(4);
//				t = (i * 6 + j)%4;
				newBox.add(new GameObject(Assets.jewel[t], new Rectangle(30+i*70, 482+j*75, 70, 70), t));
			}
		for(int i=0;i<6;i++)	addbox[i] = 0;
	}
	
	public void initCheckedMatrix(int c, int r){
		for(int i=0;i<c;i++)
			for(int j=0;j<r;j++)
				if(listBox[i][j]!=null && listBox[i][j].kind<8)	isChecked[i][j] = false;
				else	isChecked[i][j] = true;
	}
	
	public void checkForFirst(int c, int r){
		initCheckedMatrix(c, r);
		for(int i=0;i<c;i++)
			for(int j=0;j<r;j++){
				findBoxGroup(listBox[i][j]);
			}
	}
	
	public void findBoxGrouds(int col, int row, int kind){
		if(isChecked[col][row] || kind != listBox[col][row].kind || ischeckok)	return;
		else{
			isChecked[col][row] = true;
			checkbox.add(listBox[col][row]);
			if(checkbox.size>=3)	ischeckok = true;
			if(col<5)	findBoxGrouds(col+1, row, kind);
			if(row<5)	findBoxGrouds(col, row+1, kind);
			if(col>0)	findBoxGrouds(col-1, row, kind);
			if(row>0)	findBoxGrouds(col, row-1, kind);
		}
	}
	
	public void findBoxGroup(GameObject o){
		int col = (int)(o.rec.x-30)/boxBound;
		int row = (int)(o.rec.y-50)/boxBound;
		if(col<0)	col = 0;
		if(col>=6)	col = 5;
		findBoxGrouds(col, row, o.kind);
		if(checkbox.size<3)
			checkbox.clear();
		else{
			ischeckok = true;
		}
	}
	
	public void checkCollisionInColumn(GameObject o){
		if(o.isBottomCollision){
			return;
		}
		int r = (int)(o.rec.y-(playBounds.y+10))/boxBound;
		for(GameObject b:newBox)
			if(r<6 && o!=b && o.rec.x==b.rec.x && o.rec.y>b.rec.y && o.rec.y<=b.rec.y+boxBound){
				o.rec.y = b.rec.y+boxBound;
				o.velocity.y *= -.2f;
			}
		
		int c = (int)(o.rec.x-playBounds.x)/boxBound;
		if(c<0)		c = 0;
		if(c>5)		c = 5;
		if(r>5) 	r = 5;
		if(r<0)		r = 0;
		while(r>=0 && listBox[c][r]==null)	r --;
		r ++;
		if(r<6 && o.rec.y<=playBounds.y+10+r*boxBound){
			o.rec.y = playBounds.y+10+r*boxBound;
			o.velocity.y *= -.2f;
			if(o.velocity.y<10){
				o.velocity.y = 0;
				if(listBox[c][r]!=null && r<5)	r++;
				o.rec.y = playBounds.y+10+r*boxBound;
				o.isBottomCollision = true;
				listBox[c][r] = o;
			}
		}
	}
	
	public void update(float delta){
		time += delta;
		if(time>=nexttime){
			zombies.add(new Zombie(Assets.zombie_scml, 500, 650, new Vector2(500, 2000)));
			nexttime = 5 + rand.nextFloat()*5;
			time = 0;
		}
		for(int i=dameStages.size-1;i>=0;i--){
			dameStages.get(i).update(delta);
			if(dameStages.get(i).isTimeUp())
				dameStages.removeIndex(i);
		}
		for(int i=zombies.size-1;i>=0;i--){
			zombies.get(i).update(delta);
			if(zombies.get(i).isDead())
				zombies.removeIndex(i);
		}
		for(int i=plantStages.size-1;i>=0;i--){
			plantStages.get(i).update(delta);
			if(plantStages.get(i).isTimeUp())
				plantStages.removeIndex(i);
		}
		for(int i=bullets.size-1;i>=0;i--){
			bullets.get(i).update(delta);
			if(zombies.size>0){
				for(Zombie z: zombies)
					if(!z.isdying && bullets.get(i).x>=z.x){
						dameStages.add(new DamageStage(z.x, z.y, bullets.get(i).damage));
						zombies.get(0).takeDamage(bullets.get(i).damage);
						bullets.removeIndex(i);
						break;
					}
			}
		}
		for(int i=0;i<newBox.size;i++){
			newBox.get(i).takeGravityForce(gravity, .8f, delta);
			checkCollisionInColumn(newBox.get(i));
			if(newBox.get(i).isBottomCollision){
				newBox.removeIndex(i);
			}
		}
		for(int i=0;i<6;i++){
			for(int j=0;j<6;j++){
				if(listBox[i][j]!=null && listBox[i][j].isterminated){
					listBox[i][j] = null;
					addbox[i] += 1;
				}
			}
			
			int j = 0;
			while(j<6 && listBox[i][j]!=null)		j ++;
			while(j<6){
				if(listBox[i][j]!=null){
					listBox[i][j].isBottomCollision = false;
					newBox.add(listBox[i][j]);
					listBox[i][j] = null;
				}
				j ++;
			}
		}
		addBox();
	}
	
	public void draw(float delta){
		GLCommon gl = Gdx.gl;
		gl.glClearColor(1, 1, 1, 1);
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
		guiCam.update();
		batcher.setProjectionMatrix(guiCam.combined);
		batcher.enableBlending();
		batcher.begin();

		batcher.draw(Assets.table, 30, 50);
		for(int i=0;i<chosedBox.size-1;i++){
			batcher.draw(Assets.line, chosedBox.get(i).rec.x+35, chosedBox.get(i).rec.y+15, 0, 19,
					Math.max(Math.abs(chosedBox.get(i).rec.x-chosedBox.get(i+1).rec.x), Math.abs(chosedBox.get(i).rec.y-chosedBox.get(i+1).rec.y)), 38,
					1, 1, getRotation(chosedBox.get(i), chosedBox.get(i+1)));
		}
		for(int i=0;i<6;i++)
			for(int j=0;j<6;j++)
				if(listBox[i][j]!=null)
					batcher.draw(listBox[i][j].image, listBox[i][j].rec.x, listBox[i][j].rec.y,
							listBox[i][j].rec.width, listBox[i][j].rec.height);
		for(GameObject o: newBox){
			batcher.draw(o.image, o.rec.x, o.rec.y, o.rec.width, o.rec.height);
		}
		
		for(Zombie z:zombies){
			z.draw(bmsRenderer);
		}
		
		for(PlantStage p: plantStages){
			batcher.setColor(1, 1, 1, p.getColor());
			batcher.draw(p.image, p.x, p.y);
		}
		batcher.setColor(1, 1, 1, 1);
		
		for(BulletObject b: bullets){
			batcher.draw(b.image, b.x, b.y);
		}
		
		for(DamageStage d: dameStages){
			Assets.fontDamage.draw(batcher, "-"+d.numb, d.x-Assets.fontDamage.getBounds("-"+d.numb).width/2, d.y+40);
		}
		
		batcher.end();
	}
	
	public float getRotation(GameObject o1, GameObject o2){
		int x = (int)(o2.rec.x - o1.rec.x);
		int y = (int)(o2.rec.y - o1.rec.y);
		if(x==0){
			if(y>0)		return 90;
			else		return -90;
		}
		if(y==0){
			if(x>0)		return 0;
			else		return 180;
		}
		if(x>0 && y>0)	return 45;
		if(x>0 && y<0)	return -45;
		if(x<0 && y>0)	return 135;
		return -135;
	}

	@Override
	public void render(float delta) {
		update(delta);
		draw(delta);
	}
	
	public boolean isNeightbor(GameObject o1, GameObject o2){
		int c1 = (int)(o1.rec.x-30)/70;
		int r1 = (int)(o1.rec.y-50)/70;
		int c2 = (int)(o2.rec.x-30)/70;
		int r2 = (int)(o2.rec.y-50)/70;
		
		return Math.abs(c1-c2)<=1 && Math.abs(r1-r2)<=1;
	}
	
	public void getBox(int x, int y){
		int c = (x-30)/70;
		int r = (y-50)/70;
		if(c<0)		c = 0;
		if(c>5)		c = 5;
		if(r<0)		r = 0;
		if(r>5)		r = 5;
		if(listBox[c][r]!=null)
		if(!listBox[c][r].ischosed){
			if(!listBox[c][r].isterminated && (chosedBox.size==0  
				|| (listBox[c][r].kind==chosedBox.get(chosedBox.size-1).kind && isNeightbor(listBox[c][r], chosedBox.get(chosedBox.size-1)))
				)){
				chosedBox.add(listBox[c][r]);
				listBox[c][r].ischosed = true;
			}
		}
		else{
			int i=0;
			while(listBox[c][r]!=chosedBox.get(i++));
//			i++;
			while(i<chosedBox.size){
				chosedBox.get(i).ischosed = false;
				chosedBox.removeIndex(i);
			}
		}	
	}
	
	public void destroyBoxes(){
		if(chosedBox.size>=3){
			for(GameObject o: chosedBox){
				o.isterminated = true;
			}
			plantStages.add(new PlantStage(Assets.peashooter, 0, 680));
			bullets.add(new BulletObject(Assets.pea_bullet, 0, 630, (70+rand.nextInt(10))*chosedBox.size));
		}
		
		for(GameObject o: chosedBox){
			o.ischosed = false;
		}
		chosedBox.clear();
	}

	@Override
	public boolean touchDown(int x, int y, int pointer, int button) {
		guiCam.unproject(touchpos.set(Gdx.input.getX(), Gdx.input.getY(), 0));
		x = (int)touchpos.x;
		y = (int)touchpos.y;
		
		if(OverlapTester.pointInRectangle(playBounds, x, y)){
			getBox(x, y);
		}
		return false;
	}

	@Override
	public boolean touchUp(int x, int y, int pointer, int button) {
		guiCam.unproject(touchpos.set(Gdx.input.getX(), Gdx.input.getY(), 0));
		x = (int)touchpos.x;
		y = (int)touchpos.y;
		
		destroyBoxes();
		
		return false;
	}

	@Override
	public boolean touchDragged(int x, int y, int pointer) {
		guiCam.unproject(touchpos.set(Gdx.input.getX(), Gdx.input.getY(), 0));
		x = (int)touchpos.x;
		y = (int)touchpos.y;
		
		if(OverlapTester.pointInRectangle(playBounds, x, y)){
			getBox(x, y);
		}
		return false;
	}

	@Override
	public boolean keyDown(int keycode) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean keyUp(int keycode) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean keyTyped(char character) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean mouseMoved(int screenX, int screenY) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean scrolled(int amount) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void resize(int width, int height) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void show() {
		Gdx.input.setInputProcessor(this);
		setNewGame();
	}

	@Override
	public void hide() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void pause() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void resume() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void dispose() {
		// TODO Auto-generated method stub
		
	}
	
}
